package vn.lumi.smarthome.network;

import java.io.UnsupportedEncodingException;

import vn.lumi.smarthome.LumiHome;
import vn.lumi.smarthome.R;
import vn.lumi.smarthome.io.database.TBL_DeviceScene;
import vn.lumi.smarthome.io.database.TBL_DeviceState;
import vn.lumi.smarthome.io.database.TBL_Scene;
import vn.lumi.smarthome.io.model.Device;
import vn.lumi.smarthome.io.model.Scene;
import vn.lumi.smarthome.io.model.Time;
import vn.lumi.smarthome.ulti.Preference;

import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.util.Log;

public class EditScene extends AppMsg{

	private static final String TAG = "EditScene";
	//attributes
	private String sceneName = "";
	private int Scene_id = 0;
	private int room_id;
	private int mode = Scene.SCENE_MODE_NORMAL;
	private Time turnOnTime = new Time();
	private int newConfigVersion = 0;

	private int[] unchangedNormalDevicesID = null;
	private int[] unchangedNormalDevicesState = null;
	private int NumOfUnchangedNormalDevices = 0;
	
	private int[] unchangedRGBsID = null;
	private int[] unchangedRGBsState = null;
	private int NumOfUnchangedRGBs = 0;
	
	private int[] changedNormalDevicesID = null;
	private int[] changedNormalDevicesState = null;
	private int NumOfChangedNormalDevices = 0;
	
	private int[] changedRGBsID = null;
	private int[] changedRGBsState = null;
	private int NumOfChangedRGBs = 0;
	
	private int[] newNormalDevicesID = null;
	private int[] newNormalDevicesState = null;
	private int NumOfNewNormalDevices = 0;
	
	private int[] newRGBsID = null;
	private int[] newRGBsState = null;
	private int NumOfNewRGBs = 0;
	
	private int[] deletedNormalDevicesID = null;
	private int NumOfDeletedNormalDevices = 0;
	
	private int[] deletedRGBsID = null;
	private int NumOfDeletedRGBs = 0;
	
	public EditScene(int Msg_id, int uid, int sid, String newSceneName, int scene_id, int room_id, int scene_mode, int hour, int minute,
			int[] unchangedNormalDevicesID, int[] unchangedNormalDevicesState, int[] unchangedRGBsID, int[] unchangedRGBsState,
			int[] changedNormalDevicesID, int[] changedNormalDevicesState, int[] changedRGBsID, int[] changedRGBsState,
			int[] newNormalDevicesID, int[] newNormalDevicesState, int[] newRGBsID, int[] newRGBsState,
			int[] deletedNormalDevicesID, int[] deletedRGBsID) {
		super(NetMessage.CMD_APP_EDIT_SCENE, Msg_id, uid, sid);
		// TODO Auto-generated constructor stub
		sceneName = newSceneName;
		Scene_id = scene_id;
		this.Scene_id = scene_id;
		this.room_id = room_id;
		this.mode = scene_mode;
		this.turnOnTime = new Time(hour,minute);

		this.unchangedNormalDevicesID = unchangedNormalDevicesID;
		this.unchangedNormalDevicesState = unchangedNormalDevicesState;
		this.unchangedRGBsID = unchangedRGBsID;
		this.unchangedRGBsState = unchangedRGBsState;
		
		this.changedNormalDevicesID = changedNormalDevicesID;
		this.changedNormalDevicesState = changedNormalDevicesState;
		this.changedRGBsID = changedRGBsID;
		this.changedRGBsState = changedRGBsState;
		
		this.newNormalDevicesID = newNormalDevicesID;
		this.newNormalDevicesState = newNormalDevicesState;
		this.newRGBsID = newRGBsID;
		this.newRGBsState = newRGBsState;
		
		this.deletedNormalDevicesID = deletedNormalDevicesID;
		this.deletedRGBsID = deletedRGBsID;
		
		if(this.unchangedNormalDevicesID == null) this.NumOfUnchangedNormalDevices = 0;
		else this.NumOfUnchangedNormalDevices = this.unchangedNormalDevicesID.length;
		
		if(this.unchangedRGBsID == null) this.NumOfUnchangedRGBs = 0;
		else this.NumOfUnchangedRGBs = this.unchangedRGBsID.length;
		
		if(this.changedNormalDevicesID == null) this.NumOfChangedNormalDevices = 0;
		else this.NumOfChangedNormalDevices = this.changedNormalDevicesID.length;
		
		if(this.changedRGBsID == null) this.NumOfChangedRGBs = 0;
		else this.NumOfChangedRGBs = this.changedRGBsID.length;
		
		if(this.newNormalDevicesID == null) this.NumOfNewNormalDevices = 0;
		else this.NumOfNewNormalDevices = this.newNormalDevicesID.length;
		
		if(this.newRGBsID == null) this.NumOfNewRGBs = 0;
		else this.NumOfNewRGBs = this.newRGBsID.length;
		
		if(this.deletedNormalDevicesID == null) this.NumOfDeletedNormalDevices = 0;
		else this.NumOfDeletedNormalDevices = this.deletedNormalDevicesID.length;
		
		if(this.deletedRGBsID == null) this.NumOfDeletedRGBs = 0;
		else this.NumOfDeletedRGBs = this.deletedRGBsID.length;
	}

	@Override
	public byte[] generateByteArray() {
		// TODO Auto-generated method stub
		int NumOfNormalDevices = this.NumOfUnchangedNormalDevices + this.NumOfChangedNormalDevices + this.NumOfDeletedNormalDevices + this.NumOfNewNormalDevices;
		int NumOfRGBs = this.NumOfUnchangedRGBs + this.NumOfChangedRGBs + this.NumOfDeletedRGBs + this.NumOfNewRGBs;
		byte[] result = new byte[41 + NumOfNormalDevices*2 + NumOfRGBs*4];
		result[0] = (byte) this.Cmd_id;
		result[1] = (byte) this.Msg_id;
		result[2] = (byte) this.user_id;
		result[3] = (byte) this.session_id;
		result[4] = (byte) this.Scene_id;
		result[5] = (byte) this.room_id;
		
		byte[] name = null;
		try {
			name = this.sceneName.getBytes("UTF-16BE");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for(int i = 0;i<30;i++){
			if(i>=name.length) result[6+i] = 0;
			else result[6+i] = name[i];
		}
		
		result[36] = (byte) this.mode;
		result[37] = (byte) this.turnOnTime.getHour();
		result[38] = (byte) this.turnOnTime.getMinute();
		result[39] = (byte) NumOfNormalDevices;
		result[40] = (byte) NumOfRGBs;
		
		int startPos=41;
		for(int i = 0; i<NumOfChangedNormalDevices; i++){
			result[startPos+2*i] = (byte) this.changedNormalDevicesID[i];
			result[startPos+2*i+1] = (byte) this.changedNormalDevicesState[i];
		}
		startPos += 2*NumOfChangedNormalDevices;

		for(int i = 0; i<NumOfUnchangedNormalDevices; i++){
			result[startPos+2*i] = (byte) this.unchangedNormalDevicesID[i];
			result[startPos+2*i+1] = (byte) this.unchangedNormalDevicesState[i];
		}
		startPos += 2*NumOfUnchangedNormalDevices;
		
		for(int i = 0; i<NumOfNewNormalDevices; i++){
			result[startPos+2*i] = (byte) this.newNormalDevicesID[i];
			result[startPos+2*i+1] = (byte) this.newNormalDevicesState[i];
		}
		startPos += 2*NumOfNewNormalDevices;
		
		for(int i = 0; i<NumOfDeletedNormalDevices; i++){
			result[startPos+2*i] = (byte) this.deletedNormalDevicesID[i];
			result[startPos+2*i+1] = (byte) Device.DEVICE_STATE_DEVICE_REMOVED;
		}
		startPos += 2*NumOfDeletedNormalDevices;
		
		for(int i = 0; i<this.NumOfUnchangedRGBs; i++){
			result[startPos+4*i] = (byte) this.unchangedRGBsID[i];
			result[startPos+4*i+1] = (byte) this.unchangedRGBsState[3*i];
			result[startPos+4*i+2] = (byte) this.unchangedRGBsState[3*i+1];
			result[startPos+4*i+3] = (byte) this.unchangedRGBsState[3*i+2];
		}
		startPos += 4*this.NumOfUnchangedRGBs;
		
		for(int i = 0; i<this.NumOfChangedRGBs; i++){
			result[startPos+4*i] = (byte) this.changedRGBsID[i];
			result[startPos+4*i+1] = (byte) this.changedRGBsState[3*i];
			result[startPos+4*i+2] = (byte) this.changedRGBsState[3*i+1];
			result[startPos+4*i+3] = (byte) this.changedRGBsState[3*i+2];
		}
		startPos += 4*this.NumOfChangedRGBs;
		
		for(int i = 0; i<this.NumOfNewRGBs; i++){
			result[startPos+4*i] = (byte) this.newRGBsID[i];
			result[startPos+4*i+1] = (byte) this.newRGBsState[3*i];
			result[startPos+4*i+2] = (byte) this.newRGBsState[3*i+1];
			result[startPos+4*i+3] = (byte) this.newRGBsState[3*i+2];
		}
		startPos += 4*this.NumOfNewRGBs;
		
		for(int i = 0; i<this.NumOfDeletedRGBs; i++){
			result[startPos+4*i] = (byte) this.deletedRGBsID[i];
			result[startPos+4*i+1] = (byte)  Device.DEVICE_STATE_DEVICE_REMOVED;
			result[startPos+4*i+2] = (byte)  Device.DEVICE_STATE_DEVICE_REMOVED;
			result[startPos+4*i+3] = (byte)  Device.DEVICE_STATE_DEVICE_REMOVED;
		}
		startPos += 4*this.NumOfDeletedRGBs;
		return result;
	}

	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		
		// TODO Auto-generated method stub
		dest.writeInt(this.Cmd_id);
		dest.writeInt(this.length);
		dest.writeInt(this.Msg_id);
		dest.writeInt(this.session_id);
		dest.writeInt(this.user_id);
		dest.writeInt(this.Scene_id);
		dest.writeInt(room_id);
		dest.writeString(sceneName);
		dest.writeInt(this.mode);
		dest.writeInt(this.turnOnTime.getHour());
		dest.writeInt(this.turnOnTime.getMinute());

		dest.writeInt(this.NumOfUnchangedNormalDevices);
		dest.writeInt(this.NumOfUnchangedRGBs);
		dest.writeInt(this.NumOfChangedNormalDevices);
		dest.writeInt(this.NumOfChangedRGBs);
		dest.writeInt(this.NumOfNewNormalDevices);
		dest.writeInt(this.NumOfNewRGBs);
		dest.writeInt(this.NumOfDeletedNormalDevices);
		dest.writeInt(this.NumOfDeletedRGBs);
		
		dest.writeIntArray(unchangedNormalDevicesID);
		dest.writeIntArray(unchangedNormalDevicesState);		
		dest.writeIntArray(unchangedRGBsID);
		dest.writeIntArray(unchangedRGBsState);
		
		dest.writeIntArray(changedNormalDevicesID);
		dest.writeIntArray(changedNormalDevicesState);		
		dest.writeIntArray(changedRGBsID);
		dest.writeIntArray(changedRGBsState);
		
		dest.writeIntArray(newNormalDevicesID);
		dest.writeIntArray(newNormalDevicesState);		
		dest.writeIntArray(newRGBsID);
		dest.writeIntArray(newRGBsState);
		
		dest.writeIntArray(deletedNormalDevicesID);
		dest.writeIntArray(deletedRGBsID);
		
	}
	
	@Override
	public void doIfSendSuccessful(Context context) {
		Log.d(TAG, "doIfSendSuccessful");
		
		// TODO Auto-generated method stub
		//save scene into database
		ContentValues values = new ContentValues();
		values.put(TBL_Scene.NAME, sceneName);
		values.put(TBL_Scene.STATE, Scene.SCENE_STATE_OFF);
		values.put(TBL_Scene.MODE, this.mode);
		values.put(TBL_Scene.HOUR, this.turnOnTime.getHour());
		values.put(TBL_Scene.MINUTE, this.turnOnTime.getMinute());
		String selection = new String(TBL_Scene._ID+"=?");
		String[] selectionArgs = new String[]{this.Scene_id+""};
		context.getContentResolver().update(TBL_Scene.CONTENT_URI_SCENE, values, selection, selectionArgs);
		
		//update device states
			//changed normal devices
		for(int i=0;i<this.NumOfChangedNormalDevices;i++){
			//find state id
			selection = new String(TBL_DeviceScene.DEVICE_ID+"=?" +" AND " +TBL_DeviceScene.SCENE_ID+"=?");
			selectionArgs = new String[]{String.valueOf(this.changedNormalDevicesID[i]), String.valueOf(this.Scene_id)};
			String[] projection = new String[]{TBL_DeviceScene.STATE_ID};
			Cursor cursor = context.getContentResolver().query(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, projection, selection, selectionArgs, null);
			if(cursor == null) continue;
			cursor.moveToFirst();
			int stateID = cursor.getInt(cursor.getColumnIndex(TBL_DeviceScene.STATE_ID));
			
			//update device state
			ContentValues  contentValues=new ContentValues();
			contentValues.put(TBL_DeviceState.VALUE, this.changedNormalDevicesState[i]);
			contentValues.put(TBL_DeviceState.BLIND_STATE, Device.DEVICE_STATE_BLIND_STATE_STOPPED);
			selection = new String(TBL_DeviceState.ID +"=?");
			selectionArgs = new String[]{stateID+""};
			context.getContentResolver().update(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, contentValues, selection, selectionArgs);
		}
			//changed rgbs
		for(int i=0;i<this.NumOfChangedRGBs;i++){
			//find state id
			selection = new String(TBL_DeviceScene.DEVICE_ID+"=?" +" AND " +TBL_DeviceScene.SCENE_ID+"=?");
			selectionArgs = new String[]{String.valueOf(this.changedRGBsID[i]), String.valueOf(this.Scene_id)};
			String[] projection = new String[]{TBL_DeviceScene.STATE_ID};
			Cursor cursor = context.getContentResolver().query(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, projection, selection, selectionArgs, null);
			if(cursor == null) continue;
			cursor.moveToFirst();
			int stateID = cursor.getInt(cursor.getColumnIndex(TBL_DeviceScene.STATE_ID));
			
			//update device state
			ContentValues  contentValues=new ContentValues();
			int color = this.changedRGBsState[3*i] * 256*256 + this.changedRGBsState[3*i+1] *256 + this.changedRGBsState[3*i+2];
			contentValues.put(TBL_DeviceState.RGB, color);
			selection = new String(TBL_DeviceState.ID +"=?");
			selectionArgs = new String[]{stateID+""};
			context.getContentResolver().update(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, contentValues, selection, selectionArgs);
		}
		
		//insert device states
			//new normal devices
		for(int i=0;i<this.NumOfNewNormalDevices;i++){
			//insert device state
			ContentValues  contentValues=new ContentValues();
			contentValues.put(TBL_DeviceState.VALUE, this.newNormalDevicesState[i]);
			contentValues.put(TBL_DeviceState.BLIND_STATE, Device.DEVICE_STATE_BLIND_STATE_STOPPED);
			Uri uri2= context.getContentResolver().insert(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, contentValues);
			int state_id=Integer.parseInt(uri2.getLastPathSegment());
			
			//Insert to DeviceScene
			contentValues.clear();
			contentValues.put(TBL_DeviceScene.DEVICE_ID,this.newNormalDevicesID[i]);
			contentValues.put(TBL_DeviceScene.SCENE_ID,this.Scene_id);
			contentValues.put(TBL_DeviceScene.STATE_ID,state_id);
			context.getContentResolver().insert(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, contentValues);
		}
			//rgbs
		for(int i=0;i<this.NumOfNewRGBs;i++){
			//insert device state
			ContentValues  contentValues=new ContentValues();
			int color = this.newRGBsState[3*i] * 256*256 + this.newRGBsState[3*i+1] *256 + this.newRGBsState[3*i+2];
			contentValues.put(TBL_DeviceState.RGB, color);
			Uri uri2= context.getContentResolver().insert(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, contentValues);
			int state_id=Integer.parseInt(uri2.getLastPathSegment());
			
			//(3) Insert to DeviceScene
			contentValues.clear();
			contentValues.put(TBL_DeviceScene.DEVICE_ID,this.newRGBsID[i]);
			contentValues.put(TBL_DeviceScene.SCENE_ID,this.Scene_id);
			contentValues.put(TBL_DeviceScene.STATE_ID,state_id);
			context.getContentResolver().insert(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, contentValues);
		}
		
		//delete device states
			//delete normal devices
		for(int i=0;i<this.NumOfDeletedNormalDevices;i++){
			//find state id
			selection = new String(TBL_DeviceScene.DEVICE_ID+"=?" +" AND " +TBL_DeviceScene.SCENE_ID+"=?");
			selectionArgs = new String[]{String.valueOf(this.deletedNormalDevicesID[i]), String.valueOf(this.Scene_id)};
			String[] projection = new String[]{TBL_DeviceScene.STATE_ID};
			Cursor cursor = context.getContentResolver().query(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, projection, selection, selectionArgs, null);
			if(cursor == null) continue;
			cursor.moveToFirst();
			
			String[] columnNames = cursor.getColumnNames();
			for(int i2 = 0; i2<columnNames.length;i2++){
				Log.d("EditScene","column name="+columnNames[i2]);
			}
			
			int stateID = cursor.getInt(cursor.getColumnIndex(TBL_DeviceScene.STATE_ID));
			
			//delete devicescene
			context.getContentResolver().delete(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, selection, selectionArgs);
			
			//delete device state
			selection = new String(TBL_DeviceState.ID +"=?");
			selectionArgs = new String[]{stateID+""};
			context.getContentResolver().delete(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, selection, selectionArgs);
		}
			//rgbs
		for(int i=0;i<this.NumOfDeletedRGBs;i++){
			//find state id
			selection = new String(TBL_DeviceScene.DEVICE_ID+"=?" +" AND " +TBL_DeviceScene.SCENE_ID+"=?");
			selectionArgs = new String[]{String.valueOf(this.deletedRGBsID[i]), String.valueOf(this.Scene_id)};
			String[] projection = new String[]{TBL_DeviceScene.STATE_ID};
			Cursor cursor = context.getContentResolver().query(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, projection, selection, selectionArgs, null);
			if(cursor == null) continue;
			cursor.moveToFirst();
			int stateID = cursor.getInt(cursor.getColumnIndex(TBL_DeviceScene.STATE_ID));
			
			//delete devicescene
			context.getContentResolver().delete(TBL_DeviceScene.CONTENT_URI_DEVICE_SCENE, selection, selectionArgs);
			
			//delete device state
			selection = new String(TBL_DeviceState.ID +"=?");
			selectionArgs = new String[]{stateID+""};
			context.getContentResolver().delete(TBL_DeviceState.CONTENT_URI_DEVICE_STATE, selection, selectionArgs);
		}
		
		//save config in preferences
		LumiHome.HC_Config_ver = this.newConfigVersion;
		Preference.saveConfigVersion(context, this.newConfigVersion);
				
		
		//inform UI
	    Intent intent = new Intent();
	    intent.setAction(context.getString(R.string.txt_vn_lumi_smarthome_edit_scene_successful));
	    context.sendBroadcast(intent);
	    Log.d(TAG, "send broadcast success");
		
	}

	@Override
	public void doIfSendFail(Context context) {
		// TODO Auto-generated method stub
		//inform UI
	    Intent intent = new Intent();
	    intent.setAction(context.getString(R.string.txt_vn_lumi_smarthome_edit_scene_failed));
	    context.sendBroadcast(intent);
	    Log.d(TAG, "send broadcast failed");
	}

	@Override
	public void readFromParcel(Parcel in) {
		// TODO Auto-generated method stub
		Cmd_id = in.readInt();
		length = in.readInt();
		Msg_id = in.readInt();
		session_id = in.readInt();
		user_id = in.readInt();
		Scene_id= in.readInt();
		room_id = in.readInt();
		sceneName = in.readString();
		mode = in.readInt();
		turnOnTime = new Time(in.readInt(), in.readInt());
		
		this.NumOfUnchangedNormalDevices = in.readInt();
		this.NumOfUnchangedRGBs = in.readInt();
		this.NumOfChangedNormalDevices = in.readInt();
		this.NumOfChangedRGBs = in.readInt();
		this.NumOfNewNormalDevices = in.readInt();
		this.NumOfNewRGBs = in.readInt();
		this.NumOfDeletedNormalDevices = in.readInt();
		this.NumOfDeletedRGBs = in.readInt();
		
		in.readIntArray(unchangedNormalDevicesID);
		in.readIntArray(unchangedNormalDevicesState);		
		in.readIntArray(unchangedRGBsID);
		in.readIntArray(unchangedRGBsState);
		
		in.readIntArray(changedNormalDevicesID);
		in.readIntArray(changedNormalDevicesState);		
		in.readIntArray(changedRGBsID);
		in.readIntArray(changedRGBsState);
		
		in.readIntArray(newNormalDevicesID);
		in.readIntArray(newNormalDevicesState);		
		in.readIntArray(newRGBsID);
		in.readIntArray(newRGBsState);
		
		in.readIntArray(deletedNormalDevicesID);
		in.readIntArray(deletedRGBsID);
	}

	@Override
	public boolean isCorrectReply(byte[] input, int length) {
		// TODO Auto-generated method stub
		boolean result = false;
		AckScene ack = new AckScene();
		if(ack.isCorrectFormat(input, length)){
			ack.parseMessage(input, length);
			if(ack.getMsg_id() == this.Msg_id
					&&ack.getUserId() == this.getUid()) {
//				this.Scene_id = ack.getSceneID();
				this.newConfigVersion = ack.getConfigVersion();
				result = true;
			}
		}
		return result;
	}

	/* (non-Javadoc)
	 * @see vn.lumi.smarthome.network.AppMsg#isCorrectBusy(byte[], int)
	 */
	@Override
	public boolean isCorrectBusy(byte[] input, int length) {
		// TODO Auto-generated method stub
		boolean result =false;
		HC_ACK_BUSY ack_busy = new HC_ACK_BUSY();
		if(ack_busy.isCorrectFormatBusy(input, length)){
			ack_busy.parseMessage(input, length);
			if(ack_busy.getMsg_id() == this.Msg_id) result = true;
		}
		return result; 
	}

	/* (non-Javadoc)
	 * @see vn.lumi.smarthome.network.AppMsg#doIfHcBusying()
	 */
	@Override
	public void doIfHcBusying() {
		// TODO Auto-generated method stub
		
	}

}
